from flask import request
from marshmallow import Schema, fields, ValidationError
from collections import UserDict


class RequestInfo(UserDict):

    def __init__(self):
        super().__init__()
        self._dict = {}

    def __getitem__(self, key):
        return getattr(self, key, None)

    @property
    def to_dict(self):
        return self._dict

    @to_dict.setter
    def to_dict(self, value):
        self._dict = value


class Result(UserDict):
    def __init__(self):
        super().__init__()
        self._headers = RequestInfo()
        self._body = RequestInfo()

    def __getitem__(self, key):
        return getattr(self, key, None)

    @property
    def headers(self):
        return self._headers

    @headers.setter
    def headers(self, value):
        self._headers._dict = value
        if isinstance(value, dict):
            for k, v in value.items():
                setattr(self.headers, k, v)
        elif isinstance(value, list):
            setattr(self.headers, "data", value)

    @property
    def body(self):
        return self._body

    @body.setter
    def body(self, value):
        self._body._dict = value
        if isinstance(value, dict):
            for k, v in value.items():
                setattr(self.body, k, v)
        elif isinstance(value, list):
            setattr(self.body, "data", value)


class RequestVerifier:
    Result = Result

    def __init__(self, headers_schema=None, body_schema=None):
        self.headers_schema = None
        self.body_schema = None
        if headers_schema:
            self.headers_schema = headers_schema()
        if body_schema:
            self.body_schema = body_schema()

    def verify_headers(self):
        headers = {
            k.lower(): v
            for k, v in request.headers.items()
        }
        headers_schema = self.headers_schema
        try:
            validated_headers = headers_schema.load(headers)
            return validated_headers
        except ValidationError as e:
            return {"code": 400, "data": {}, 'msg': e.messages}, 400

    def verify_request(self):
        data = request.get_json()
        body_schema = self.body_schema
        try:
            validated_data = body_schema.load(data)
            return validated_data
        except ValidationError as e:
            return {"code": 400, "data": {}, 'msg': e.messages}, 400

    def verify(self):
        result = Result()
        if self.headers_schema:
            headers_result = self.verify_headers()
            if isinstance(headers_result, tuple):
                return headers_result
            else:
                result.headers = headers_result

        if self.body_schema:
            body_result = self.verify_request()
            if isinstance(body_result, tuple):
                return body_result
            else:
                result.body = body_result

        return result


class BaseSchema(Schema):

    def load(self, data, *, many: bool | None = None, partial: bool = None, unknown: str | None = None, ):
        """
        重写load方法，只校验传入的data中存在的字段，不校验传入的data中不存在的字段
        :param data:
        :param many:
        :param partial:
        :param unknown:
        :return:
        """
        validated_data = {}
        for field_name, field in self.fields.items():
            value = data.get(field_name, None)
            if value is not None:
                try:
                    validated_value = field.deserialize(value)
                    validated_data[field_name] = validated_value
                except ValidationError as e:
                    raise ValidationError({field_name: e.messages})
        return validated_data


class HeadersSchema(BaseSchema):
    token = fields.String(required=True)
    content_type = fields.String(required=True)
    trace_id = fields.String(required=True)
